"""
Singleton metaclass, for creating singleton classes. It's pretty basic, there
are more advanced singleton metaclasses online, but this one is sufficient for
our purposes.

Copyright (c) 2009 Christopher Hesse
http://code.google.com/p/python-expect/
"""

import threading


class SingletonMeta(type):
    """
    An object that can only be instantiated once, any instantiation
    after that just returns the existing object.
    
    Use it like this:
    
        class SomeClass(object):
            __metaclass__ = SingletonMeta
            
    Then you can do:
    
        s1 = SomeClass()
        s2 = SomeClass()
        assert(s1 == s2)
        
    I don't recommend that the singleton takes any parameters to its
    __init__ method, as this wouldn't make a whole lot of sense since
    you'd have different instances of a Singleton.
    """
    # make the singleton metaclass thread safe
    _singleton_lock = threading.RLock()
    
    def __init__(cls, name, bases, classdict):
        # this is called when the class that uses this metaclass
        # is defined
        with SingletonMeta._singleton_lock:
            cls._instance = None
            super(SingletonMeta, cls).__init__(name, bases, classdict)
        
    def __call__(cls, *args, **kwargs):
        # normally, when a class is instantiated, the instance is created with
        # type(name, bases, dict), when it has a metaclass set, it is created
        # using the metaclass: metaclass_instance(name, bases, dict)
        # in that case, we return the instance, if it exists (stored on the class)
        # or we create a new one using the parent of this metaclass (type)
        with SingletonMeta._singleton_lock:
            if cls._instance is None:
                cls._instance = super(SingletonMeta, cls).__call__(*args, **kwargs)
        return cls._instance